package ooo.reindeer.commons.utils.queue;

import ooo.reindeer.logging.ILogger;
import ooo.reindeer.logging.LogUtil;

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public  class DelayQueue<V> {
    private static final ILogger logger = LogUtil.getLogger(SimpleDelayQueue.class);
    java.util.concurrent.DelayQueue<DelayItem<V>> queue = new java.util.concurrent.DelayQueue<>();
    static TimeUnit BASE_TIME_UNIT;
    long delayTime=0;

    public DelayQueue() {
    }

    public DelayQueue(int delayTime) {
        this.delayTime = delayTime;
    }

    public V poll(long timeout, TimeUnit unit) throws InterruptedException {
        DelayItem<V> item = (DelayItem)this.queue.poll(timeout, unit);
        return item == null ? null : item.value;
    }

    public V take() throws InterruptedException {
        DelayItem<V> item = (DelayItem)this.queue.take();
        return item.value;
    }
    public DelayItem<V> takeOriginal() {

        try {

            DelayItem<V> delayItem = queue.take();
            return delayItem;

        } catch (InterruptedException e) {
            //no thing to do
        }
        return null;
    }

    public void put(V value) {
        this.put(value,delayTime);
    }


    public void put(V value, Long timeout) {
        this.put(value, timeout, BASE_TIME_UNIT);
    }

    public void put(V value, Long timeout, TimeUnit unit) {
        this.queue.put(new DelayItem(value, BASE_TIME_UNIT.convert(timeout, unit)));
    }

    public boolean add(V value) {
        return this.add(value, delayTime);
    }


    public boolean add(V value, Long timeout) {
        return this.add(value, timeout, BASE_TIME_UNIT);
    }

    public boolean add(V value, Long timeout, TimeUnit unit) {
        return this.queue.add(new DelayItem(value, BASE_TIME_UNIT.convert(timeout, unit)));
    }

    public int size(){
        return this.queue.size();
    }

    public V get(){
        DelayItem<V> item = (DelayItem)this.queue.poll();
        return item == null ? null : item.value;
    }

    static {
        BASE_TIME_UNIT = TimeUnit.MILLISECONDS;
    }

    public static final class DelayItem<V> implements Delayed {
        V value;
        long deathLine;

        DelayItem(V x, long d) {
            this.value = x;
            this.deathLine = System.currentTimeMillis() + d;
        }

        public int compareTo(Delayed o) {
            return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));
        }

        public long getDelay(TimeUnit unit) {

            return unit.convert(this.deathLine-System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }

        public V getValue() {
            return value;
        }

        public void setTimeOut(long time_out) {
            deathLine = System.currentTimeMillis() + time_out;
        }

    }
}
